package com.caine.filter.filter;

import com.caine.common.entity.Payload;
import com.caine.common.entity.R;
import com.caine.common.entity.UserInfo;
import com.caine.common.tool.Constant;
import com.caine.common.tool.JWTTool;
import com.caine.filter.config.RsaKeyProperties;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static com.caine.common.tool.PrintTool.printMsg;

/**
 * @Author: CaineZhu
 * @Description: token合法性验证
 * @Date: Created in 17:25 2021/1/7
 * @Modified By:
 */
@Slf4j
public class TokenVerifyFilter extends BasicAuthenticationFilter {

    RsaKeyProperties prop;

    public TokenVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) {
        super(authenticationManager);
        this.prop = prop;
    }

    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith(Constant.TOKEN_HEADER)) {
            //如果携带错误的token，则给用户提示请登录！
            chain.doFilter(request, response);
            printMsg(response, R.unauthorized("请登录"));
        } else {
            try {
                //如果携带了正确格式的token要先得到token
                String token = header.replace(Constant.TOKEN_HEADER, "");
                //验证tken是否正确
                Payload<UserInfo> payload = JWTTool.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
                UserInfo user = payload.getUserInfo();
                if (user != null) {
                    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
                    user.getAuthorities().stream().forEach(s -> authorities.add(new SimpleGrantedAuthority(s)));
                    UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken(user.getUserName(), null, authorities);
                    SecurityContextHolder.getContext().setAuthentication(authResult);
                    chain.doFilter(request, response);
                }
            } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException deserializationException) {
                log.error("token不合法", deserializationException);
                printMsg(response, R.error("token不合法"));
            }
        }
    }
}
